#ifndef _GNU_SOURCE
    #define _GNU_SOURCE
#endif
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <time.h>
#include "util.h"


int main(int argc, char** argv) {

    void* buffer = alloc_hp();
    set_seed();

    FILE *dataf = fopen(argv[1], "w+");
    if(!dataf) printf("dataf error\n");
    for (size_t size = 4096; size <= 1ull<<29; size = next_size(size, 2))
    {
        printf("%6ldK ", size/1024);
        for (size_t stride = 64; stride <= (size & ~(size-1)) >> 4; stride<<=1)
        {
            struct timespec begin, end;
            double time;

            seq_addr addr(buffer, size, stride, 0);
            size_t iter = 0, len = addr.size();
            void *p = buffer;

            fill_buf(addr, thrash_order_gen(len));

            // len = fill_buf(buffer, thrash_order, size, stride, 0);

            //warmup for 1sec
            clock_gettime(CLOCK_THREAD_CPUTIME_ID, &begin);
            do
            {
                iter ++;
                p = pointer_chasing_16(p, len/16);
                clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end);
            } while (((end.tv_sec - begin.tv_sec)*(1e9) + end.tv_nsec - begin.tv_nsec) < 1e9);

            iter *= 8;

            clock_gettime(CLOCK_THREAD_CPUTIME_ID, &begin);
            p = pointer_chasing_16(p, iter*len/16);
            clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end);
            //check result, also prevent optimization
            if(p != buffer) printf("run error");

            time = ((end.tv_sec - begin.tv_sec)*(1e9) + end.tv_nsec - begin.tv_nsec)/(iter*len);
            if(dataf) fprintf(dataf, "%6ld,%6ld,%05.2lf\n", size/1024, stride, time);
            printf("%05.2lf ", time);
        }
        printf("\n");
        fflush(NULL);
    }
    

    return 0;
}
